home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / MoreFiles 1.2.1 / FSpCompat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-22  |  22.1 KB  |  746 lines  |  [TEXT/KAHL]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    FSSpec compatibility functions.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support
  7. **
  8. **    File:        FSpCompat.c
  9. **
  10. **    Copyright © 1992-1994 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #ifndef __FSPCOMPAT__
  23. #include "FSpCompat.h"
  24. #endif
  25.  
  26. /*****************************************************************************/
  27.  
  28. /* local constants */
  29.  
  30. enum {
  31.     gestaltBugFixAttrsTwo                    = 'bugy',
  32.     gestaltFSpExchangeFilesCompatibilityFix    = 26,
  33.     gestaltBugFixAttrsThree                    = 'bugx',
  34.     gestaltFSpCreateScriptSupportFix        = 1
  35. };
  36.  
  37. /*****************************************************************************/
  38.  
  39. /* static prototypes */
  40.  
  41. static    Boolean    FSHasFSSpecCalls(void);
  42.  
  43. static    Boolean    QTHasFSSpecCalls(void);
  44.  
  45. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void);
  46.  
  47. static    Boolean    HasFSpCreateScriptSupportFix(void);
  48.  
  49. static    OSErr    GenerateUniqueName(short volume,
  50.                                    long *startSeed,
  51.                                    long dir1,
  52.                                    long dir2,
  53.                                    StringPtr uniqueName);
  54.  
  55. /*****************************************************************************/
  56.  
  57. /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
  58.  
  59. static    Boolean    FSHasFSSpecCalls(void)
  60. {
  61.     long            response;
  62.     static Boolean    tested = false;
  63.     static Boolean    result = false;
  64.     
  65.     if ( !tested )
  66.     {
  67.         tested = true;
  68.         if ( Gestalt(gestaltFSAttr, &response) == noErr )
  69.         {
  70.             result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
  71.         }
  72.     }
  73.     return ( result );
  74. }
  75.  
  76. /*****************************************************************************/
  77.  
  78. /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
  79. /* except for FSpExchangeFiles. */
  80.  
  81. static    Boolean    QTHasFSSpecCalls(void)
  82. {
  83.     long            response;
  84.     static Boolean    tested = false;
  85.     static Boolean    result = false;
  86.     
  87.     if ( !tested )
  88.     {
  89.         tested = true;
  90.         /* With future Universal interface changes, the following line will */
  91.         /* need to be commented out and the commented out line will need to */
  92.         /* be uncommented. */
  93.         result = (Gestalt(gestaltQuickTime, &response) == noErr);
  94. //        result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
  95.     }
  96.     return ( result );
  97. }
  98.  
  99. /*****************************************************************************/
  100.  
  101. /* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
  102. /* compatibility code has been fixed in system software. */
  103.  
  104. Boolean    HasFSpExchangeFilesCompatibilityFix(void)
  105. {
  106.     long            response;
  107.     static Boolean    tested = false;
  108.     static Boolean    result = false;
  109.     
  110.     if ( !tested )
  111.     {
  112.         tested = true;
  113.         if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
  114.         {
  115.             result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
  116.         }
  117.     }
  118.     return ( result );
  119. }
  120.  
  121. /*****************************************************************************/
  122.  
  123. /* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
  124. /* FSpCreateResFile have been fixed in system software to correctly set */
  125. /* the scriptCode in the volume's catalog. */
  126.  
  127. Boolean    HasFSpCreateScriptSupportFix(void)
  128. {
  129.     long            response;
  130.     static Boolean    tested = false;
  131.     static Boolean    result = false;
  132.     
  133.     if ( !tested )
  134.     {
  135.         if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
  136.         {
  137.             result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
  138.         }
  139.     }
  140.     return ( result );
  141. }
  142.  
  143. /*****************************************************************************/
  144.  
  145. /*
  146. **    File Manager FSp calls
  147. */
  148.  
  149. /*****************************************************************************/
  150.  
  151. pascal    OSErr    FSMakeFSSpecCompat(short vRefNum,
  152.                                    long dirID,
  153.                                    ConstStr255Param fileName,
  154.                                    FSSpecPtr spec)
  155. {
  156.     OSErr    result;
  157.     Boolean    isDirectory;
  158.     
  159.     /* Let the file system create the FSSpec if it can since it does the job */
  160.     /* much more efficiently than I can. */
  161.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  162.     {
  163.         result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
  164.         /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
  165.         /* returned in the parID field when making an FSSpec to the volume's */
  166.         /* root directory by passing a full pathname in MakeFSSpec's */
  167.         /* fileName parameter. */
  168.         if ( (result == noErr) && (spec->parID == 0) )
  169.             spec->parID = fsRtParID;
  170.     }
  171.     else
  172.         result = GetObjectLocation(vRefNum, dirID, (StringPtr)fileName,
  173.                                     &(spec->vRefNum), &(spec->parID), spec->name,
  174.                                     &isDirectory);
  175.     return ( result );
  176. }
  177.  
  178. /*****************************************************************************/
  179.  
  180. pascal    OSErr    FSpOpenDFCompat(const FSSpec *spec,
  181.                                 char permission,
  182.                                 short *refNum)
  183. {
  184.     OSErr            result;
  185.     HParamBlockRec    pb;
  186.  
  187.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  188.         return ( FSpOpenDF(spec, permission, refNum) );
  189.     else
  190.     {
  191.         pb.ioParam.ioVRefNum = spec->vRefNum;
  192.         pb.fileParam.ioDirID = spec->parID;
  193.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  194.         pb.ioParam.ioVersNum = 0;
  195.         pb.ioParam.ioPermssn = permission;
  196.         pb.ioParam.ioMisc = NULL;
  197.         result = PBHOpenSync(&pb);    /* OpenDF not supported by System 6, so use Open */
  198.         *refNum = pb.ioParam.ioRefNum;
  199.         return ( result );
  200.     }
  201. }
  202.  
  203. /*****************************************************************************/
  204.  
  205. pascal    OSErr    FSpOpenRFCompat(const FSSpec *spec,
  206.                                 char permission,
  207.                                 short *refNum)
  208. {
  209.     OSErr            result;
  210.     HParamBlockRec    pb;
  211.  
  212.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  213.         return ( FSpOpenRF(spec, permission, refNum) );
  214.     else
  215.     {
  216.         pb.ioParam.ioVRefNum = spec->vRefNum;
  217.         pb.fileParam.ioDirID = spec->parID;
  218.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  219.         pb.ioParam.ioVersNum = 0;
  220.         pb.ioParam.ioPermssn = permission;
  221.         pb.ioParam.ioMisc = NULL;
  222.         result = PBHOpenRFSync(&pb);
  223.         *refNum = pb.ioParam.ioRefNum;
  224.         return ( result );
  225.     }
  226. }
  227.  
  228. /*****************************************************************************/
  229.  
  230. pascal    OSErr    FSpCreateCompat(const FSSpec *spec,
  231.                                 OSType creator,
  232.                                 OSType fileType,
  233.                                 ScriptCode scriptTag)
  234. {
  235.     OSErr            result;
  236.     UniversalFMPB    pb;
  237.     
  238.     if ( (FSHasFSSpecCalls() || QTHasFSSpecCalls()) && HasFSpCreateScriptSupportFix() )
  239.         return ( FSpCreate(spec, creator, fileType, scriptTag) );
  240.     else
  241.     {
  242.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  243.         pb.hPB.fileParam.ioDirID = spec->parID;
  244.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  245.         pb.hPB.fileParam.ioFVersNum = 0;
  246.         result = PBHCreateSync(&(pb.hPB));
  247.         if ( result == noErr )
  248.         {
  249.             /* get info on created item */
  250.             pb.ciPB.hFileInfo.ioFDirIndex = 0;
  251.             result = PBGetCatInfoSync(&(pb.ciPB));
  252.             if ( result == noErr )
  253.             {
  254.                 /* Set fdScript in FXInfo */
  255.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  256.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  257.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  258.                 pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  259.                                                             ((char)scriptTag | (char)0x80) :
  260.                                                             (smRoman);
  261.                 /* Set creator/fileType */
  262.                 pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  263.                 pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
  264.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  265.                 pb.ciPB.hFileInfo.ioDirID = spec->parID;
  266.                 result = PBSetCatInfoSync(&(pb.ciPB));
  267.             }
  268.         }
  269.         return ( result );
  270.     }
  271. }
  272.  
  273. /*****************************************************************************/
  274.  
  275. pascal    OSErr    FSpDirCreateCompat(const FSSpec *spec,
  276.                                    ScriptCode scriptTag,
  277.                                    long *createdDirID)
  278. {
  279.     OSErr            result;
  280.     UniversalFMPB    pb;
  281.  
  282.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  283.         return ( FSpDirCreate(spec, scriptTag, createdDirID) );
  284.     else
  285.     {
  286.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  287.         pb.hPB.fileParam.ioDirID = spec->parID;
  288.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  289.         result = PBDirCreateSync(&(pb.hPB));
  290.         *createdDirID = pb.hPB.fileParam.ioDirID;
  291.         if ( result == noErr )
  292.         {
  293.             /* get info on created item */
  294.             pb.ciPB.dirInfo.ioFDirIndex = 0;
  295.             pb.ciPB.dirInfo.ioDrDirID = spec->parID;
  296.             result = PBGetCatInfoSync(&(pb.ciPB));
  297.             if ( result == noErr )
  298.             {
  299.                 /* Set frScript in DXInfo */
  300.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  301.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  302.                 /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
  303.                 pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
  304.                                                             ((char)scriptTag | (char)0x80) :
  305.                                                             (smRoman);
  306.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  307.                 pb.ciPB.dirInfo.ioDrDirID = spec->parID;            
  308.                 result = PBSetCatInfoSync(&(pb.ciPB));
  309.             }
  310.         }
  311.         return ( result );
  312.     }
  313. }
  314.  
  315. /*****************************************************************************/
  316.  
  317. pascal    OSErr    FSpDeleteCompat(const FSSpec *spec)
  318. {
  319.     HParamBlockRec    pb;
  320.  
  321.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  322.         return ( FSpDelete(spec) );
  323.     else
  324.     {
  325.         pb.ioParam.ioVRefNum = spec->vRefNum;
  326.         pb.fileParam.ioDirID = spec->parID;
  327.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  328.         pb.ioParam.ioVersNum = 0;
  329.         return ( PBHDeleteSync(&pb) );
  330.     }
  331. }
  332.  
  333. /*****************************************************************************/
  334.  
  335. pascal    OSErr    FSpGetFInfoCompat(const FSSpec *spec,
  336.                                   FInfo *fndrInfo)
  337. {
  338.     OSErr            result;
  339.     HParamBlockRec    pb;
  340.  
  341.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  342.         return ( FSpGetFInfo(spec, fndrInfo) );
  343.     else
  344.     {
  345.         pb.fileParam.ioVRefNum = spec->vRefNum;
  346.         pb.fileParam.ioDirID = spec->parID;
  347.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  348.         pb.fileParam.ioFVersNum = 0;
  349.         pb.fileParam.ioFDirIndex = 0;
  350.         result = PBHGetFInfoSync(&pb);
  351.         *fndrInfo = pb.fileParam.ioFlFndrInfo;
  352.         return ( result );
  353.     }
  354. }
  355.  
  356. /*****************************************************************************/
  357.  
  358. pascal    OSErr    FSpSetFInfoCompat(const FSSpec *spec,
  359.                                   const FInfo *fndrInfo)
  360. {
  361.     OSErr            result;
  362.     HParamBlockRec    pb;
  363.  
  364.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  365.         return ( FSpSetFInfo(spec, fndrInfo) );
  366.     else
  367.     {
  368.         pb.fileParam.ioVRefNum = spec->vRefNum;
  369.         pb.fileParam.ioDirID = spec->parID;
  370.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  371.         pb.fileParam.ioFVersNum = 0;
  372.         pb.fileParam.ioFDirIndex = 0;
  373.         result = PBHGetFInfoSync(&pb);
  374.         if ( result == noErr )
  375.         {
  376.             pb.fileParam.ioFlFndrInfo = *fndrInfo;
  377.             pb.fileParam.ioDirID = spec->parID;
  378.             result = PBHSetFInfoSync(&pb);
  379.         }
  380.         return ( result );
  381.     }
  382. }
  383.  
  384. /*****************************************************************************/
  385.  
  386. pascal    OSErr    FSpSetFLockCompat(const FSSpec *spec)
  387. {
  388.     HParamBlockRec    pb;
  389.  
  390.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  391.         return ( FSpSetFLock(spec) );
  392.     else
  393.     {
  394.         pb.fileParam.ioVRefNum = spec->vRefNum;
  395.         pb.fileParam.ioDirID = spec->parID;
  396.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  397.         pb.fileParam.ioFVersNum = 0;
  398.         return ( PBHSetFLockSync(&pb) );
  399.     }
  400. }
  401.  
  402. /*****************************************************************************/
  403.  
  404. pascal    OSErr    FSpRstFLockCompat(const FSSpec *spec)
  405. {
  406.     HParamBlockRec    pb;
  407.  
  408.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  409.         return ( FSpRstFLock(spec) );
  410.     else
  411.     {
  412.         pb.fileParam.ioVRefNum = spec->vRefNum;
  413.         pb.fileParam.ioDirID = spec->parID;
  414.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  415.         pb.fileParam.ioFVersNum = 0;
  416.         return ( PBHRstFLockSync(&pb) );
  417.     }
  418. }
  419.  
  420. /*****************************************************************************/
  421.  
  422. pascal    OSErr    FSpRenameCompat(const FSSpec *spec,
  423.                                 ConstStr255Param newName)
  424. {
  425.     HParamBlockRec    pb;
  426.  
  427.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  428.         return ( FSpRename(spec, newName) );
  429.     else
  430.     {
  431.         pb.ioParam.ioVRefNum = spec->vRefNum;
  432.         pb.fileParam.ioDirID = spec->parID;
  433.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  434.         pb.ioParam.ioVersNum = 0;
  435.         pb.ioParam.ioMisc = (Ptr) newName;
  436.         return ( PBHRenameSync(&pb) );
  437.     }
  438. }
  439.  
  440. /*****************************************************************************/
  441.  
  442. pascal    OSErr    FSpCatMoveCompat(const FSSpec *source,
  443.                                  const FSSpec *dest)
  444. {
  445.     CMovePBRec    pb;
  446.  
  447.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  448.         return ( FSpCatMove(source, dest) );
  449.     else
  450.     {
  451.         /* source and destination volume must be the same */
  452.         if ( source->vRefNum != dest->vRefNum )
  453.             return ( paramErr );
  454.         
  455.         pb.ioNamePtr = (StringPtr) &(source->name);
  456.         pb.ioVRefNum = source->vRefNum;
  457.         pb.ioDirID = source->parID;
  458.         pb.ioNewDirID = dest->parID;
  459.         pb.ioNewName = (StringPtr) &(dest->name);
  460.         return ( PBCatMoveSync(&pb) );
  461.     }
  462. }
  463.  
  464. /*****************************************************************************/
  465.  
  466. /* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
  467. /* on the specified volume. Ripped off from Feldman's code. */
  468.  
  469. static    OSErr    GenerateUniqueName(short volume,
  470.                                    long *startSeed,
  471.                                    long dir1,
  472.                                    long dir2,
  473.                                    StringPtr uniqueName)
  474. {
  475.     OSErr            error = noErr;
  476.     long            i;
  477.     CInfoPBRec        cinfo;
  478.     
  479.     cinfo.hFileInfo.ioVRefNum = volume;
  480.     cinfo.hFileInfo.ioFDirIndex = 0;
  481.     cinfo.hFileInfo.ioNamePtr = uniqueName;
  482.  
  483.     while ( error != fnfErr )
  484.     {
  485.         (*startSeed)++;        
  486.         cinfo.hFileInfo.ioNamePtr[0] = 8;
  487.         for ( i = 1; i <= 8; i++ )
  488.         {
  489.             cinfo.hFileInfo.ioNamePtr[i] = "0123456789ABCDEF"[((*startSeed >> ((8-i)*4)) & 0xf)];
  490.         }
  491.         cinfo.hFileInfo.ioDirID = dir1;
  492.         error = fnfErr;
  493.         for ( i = 1; i <= 2; i++ )
  494.         {
  495.             error = error & PBGetCatInfoSync(&cinfo);
  496.             cinfo.hFileInfo.ioDirID = dir2;
  497.             if ( (error != fnfErr) && (error != noErr) )
  498.                 return ( error );
  499.         }
  500.     }
  501.     return ( noErr );
  502. }
  503.  
  504. /*****************************************************************************/
  505.  
  506. pascal    OSErr    FSpExchangeFilesCompat(const FSSpec *source,
  507.                                        const FSSpec *dest)
  508. {
  509.     HParamBlockRec            pb;
  510.     CInfoPBRec                catInfoSource, catInfoDest;
  511.     OSErr                    error, error2;
  512.     Str31                    unique1, unique2;
  513.     StringPtr                unique1Ptr, unique2Ptr, swapola;
  514.     GetVolParmsInfoBuffer    volInfo;
  515.     long                    theSeed, temp;
  516.     
  517.     if ( FSHasFSSpecCalls() && HasFSpExchangeFilesCompatibilityFix() )
  518.         return ( FSpExchangeFiles(source, dest) );
  519.     else
  520.     {
  521.         /* Make sure the source and destination are on the same volume */
  522.         if ( source->vRefNum != dest->vRefNum )
  523.             return ( paramErr );
  524.         
  525.         /* Try PBExchangeFiles first since it preserves the file ID reference */
  526.         pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
  527.         pb.fidParam.ioVRefNum = source->vRefNum;
  528.         pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
  529.         pb.fidParam.ioDestDirID = dest->parID;
  530.         pb.fidParam.ioSrcDirID = source->parID;
  531.     
  532.         error = PBExchangeFilesSync(&pb);
  533.     
  534.         /* Note: The compatibility case won't work for files with *Btree control blocks. */
  535.         /* Right now the only *Btree files are created by the system. */
  536.         if ( error != noErr )
  537.         {
  538.             pb.ioParam.ioNamePtr = NULL;
  539.             pb.ioParam.ioBuffer = (Ptr) &volInfo;
  540.             pb.ioParam.ioReqCount = sizeof(volInfo);
  541.             error2 = PBHGetVolParmsSync(&pb);
  542.             
  543.             /* continue if volume has no fileID support (or no GetVolParms support) */
  544.             if ( (error2 == noErr) && hasFileIDs(volInfo) )
  545.                 return ( error );
  546.     
  547.             /* Get the catalog information for each file */
  548.             /* and make sure both files are *really* files */
  549.             catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
  550.             catInfoSource.hFileInfo.ioFDirIndex = 0;
  551.             catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
  552.             catInfoSource.hFileInfo.ioDirID = source->parID;
  553.             catInfoSource.hFileInfo.filler2 = 0;
  554.             error = PBGetCatInfoSync(&catInfoSource);
  555.             if ( error != noErr )
  556.                 return ( error );
  557.             if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  558.                 return ( notAFileErr );
  559.             
  560.             catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
  561.             catInfoDest.hFileInfo.ioFDirIndex = 0;
  562.             catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
  563.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  564.             catInfoDest.hFileInfo.filler2 = 0;
  565.             error = PBGetCatInfoSync(&catInfoDest);
  566.             if ( error != noErr )
  567.                 return ( error );
  568.             if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  569.                 return ( notAFileErr );
  570.             
  571.             /* generate 2 filenames that are unique in both directories */
  572.             theSeed = 0x64666A6C;    /* a fine unlikely filename */
  573.             unique1Ptr = (StringPtr)&unique1;
  574.             unique2Ptr = (StringPtr)&unique2;
  575.             
  576.             error = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
  577.             if ( error != noErr )
  578.                 return ( error );
  579.     
  580.             GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
  581.             if ( error != noErr )
  582.                 return ( error );
  583.     
  584.             /* rename source to unique1 */
  585.             pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
  586.             pb.ioParam.ioMisc = (Ptr) unique1Ptr;
  587.             pb.ioParam.ioVersNum = 0;
  588.             error = PBHRenameSync(&pb);
  589.             if ( error != noErr )
  590.                 return ( error );        
  591.             
  592.             /* rename dest to unique2 */
  593.             pb.ioParam.ioMisc = (Ptr) unique2Ptr;
  594.             pb.ioParam.ioVersNum = 0;
  595.             pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
  596.             pb.fileParam.ioDirID = dest->parID;
  597.             error = PBHRenameSync(&pb);
  598.             if ( error != noErr )
  599.                 goto error2;    /* back out gracefully by renaming unique1 back to source */
  600.                 
  601.             /* If files are not in same directory, swap their locations */
  602.             if ( source->parID != dest->parID )
  603.             {
  604.                 /* move source file to dest directory */
  605.                 pb.copyParam.ioNamePtr = unique1Ptr;
  606.                 pb.copyParam.ioNewName = NULL;
  607.                 pb.copyParam.ioNewDirID = dest->parID;
  608.                 pb.copyParam.ioDirID = source->parID;
  609.                 error = PBCatMoveSync((CMovePBPtr) &pb);
  610.                 if ( error != noErr )
  611.                     goto error1;    /* back out gracefully by renaming both files to original names */
  612.                 
  613.                 /* move dest file to source directory */
  614.                 pb.copyParam.ioNamePtr = unique2Ptr;
  615.                 pb.copyParam.ioNewDirID = source->parID;
  616.                 pb.copyParam.ioDirID = dest->parID;
  617.                 error = PBCatMoveSync((CMovePBPtr) &pb);
  618.                 if ( error != noErr)
  619.                 {
  620.                     /* life is very bad.  We'll at least try to move source back */
  621.                     pb.copyParam.ioNamePtr = unique1Ptr;
  622.                     pb.copyParam.ioNewName = NULL;
  623.                     pb.copyParam.ioNewDirID = source->parID;
  624.                     pb.copyParam.ioDirID = dest->parID;
  625.                     (void) PBCatMoveSync((CMovePBPtr) &pb);    /* ignore errors */
  626.                     goto error1;    /* back out gracefully by renaming both files to original names */
  627.                 }
  628.             }
  629.             
  630.             /* Make unique1Ptr point to file in source->parID */
  631.             /* and unique2Ptr point to file in dest->parID */
  632.             /* This lets us fall through to the rename code below */
  633.             swapola = unique1Ptr;
  634.             unique1Ptr = unique2Ptr;
  635.             unique2Ptr = swapola;
  636.     
  637.             /* At this point, the files are in their new locations (if they were moved) */
  638.             /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
  639.             /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
  640.             /* Need to swap attributes except mod date and swap names */
  641.     
  642.             /* swap the catalog info by re-aiming the CInfoPB's */
  643.             catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
  644.             catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
  645.             
  646.             catInfoSource.hFileInfo.ioDirID = source->parID;
  647.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  648.             
  649.             /* Swap the original mod dates with each file */
  650.             temp = catInfoSource.hFileInfo.ioFlMdDat;
  651.             catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
  652.             catInfoDest.hFileInfo.ioFlMdDat = temp;
  653.             
  654.             /* Here's the swap (ignore errors) */
  655.             (void) PBSetCatInfoSync(&catInfoSource); 
  656.             (void) PBSetCatInfoSync(&catInfoDest);
  657.             
  658.             /* rename unique2 back to dest */
  659. error1:
  660.             pb.ioParam.ioMisc = (Ptr) &(dest->name);
  661.             pb.ioParam.ioVersNum = 0;
  662.             pb.fileParam.ioNamePtr = unique2Ptr;
  663.             pb.fileParam.ioDirID = dest->parID;
  664.             (void) PBHRenameSync(&pb);    /* ignore errors */
  665.     
  666.             /* rename unique1 back to source */
  667. error2:
  668.             pb.ioParam.ioMisc = (Ptr) &(source->name);
  669.             pb.ioParam.ioVersNum = 0;
  670.             pb.fileParam.ioNamePtr = unique1Ptr;
  671.             pb.fileParam.ioDirID = source->parID;
  672.             (void) PBHRenameSync(&pb); /* ignore errors */
  673.         }
  674.         return ( error );
  675.     }
  676. }
  677.  
  678. /*****************************************************************************/
  679.  
  680. /* 
  681. **    Resource Manager FSp calls
  682. */
  683.  
  684. /*****************************************************************************/
  685.  
  686. pascal    short    FSpOpenResFileCompat(const FSSpec *spec,
  687.                                      SignedByte permission)
  688. {
  689.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  690.         return ( FSpOpenResFile(spec, permission) );
  691.     else
  692.         return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
  693. }
  694.  
  695. /*****************************************************************************/
  696.  
  697. pascal    void    FSpCreateResFileCompat(const FSSpec *spec,
  698.                                        OSType creator,
  699.                                        OSType fileType,
  700.                                        ScriptCode scriptTag)
  701. {
  702.     OSErr            result;
  703.     CInfoPBRec        pb;
  704.     
  705.     if ( (FSHasFSSpecCalls() || QTHasFSSpecCalls()) && HasFSpCreateScriptSupportFix() )
  706.     {
  707.         FSpCreateResFile(spec, creator, fileType, scriptTag);
  708.         return;
  709.     }
  710.     else
  711.     {
  712.         HCreateResFile(spec->vRefNum, spec->parID, spec->name);
  713.         if ( ResError() == noErr )
  714.         {
  715.             /* get info on created item */
  716.             pb.hFileInfo.ioVRefNum = spec->vRefNum;
  717.             pb.hFileInfo.ioDirID = spec->parID;
  718.             pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
  719.             pb.hFileInfo.ioFDirIndex = 0;
  720.             result = PBGetCatInfoSync(&pb);
  721.             if ( result == noErr )
  722.             {
  723.                 /* Set fdScript in FXInfo */
  724.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  725.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  726.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  727.                 pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  728.                                                         ((char)scriptTag | (char)0x80) :
  729.                                                         (smRoman);
  730.                 /* Set creator/fileType */
  731.                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  732.                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
  733.                 
  734.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  735.                 pb.hFileInfo.ioDirID = spec->parID;
  736.                 result = PBSetCatInfoSync(&pb);
  737.             }
  738.             /* Set ResErr low memory global to result */
  739.             LMSetResErr(result);
  740.         }
  741.         return;
  742.     }
  743. }
  744.  
  745. /*****************************************************************************/
  746.